/*
 *   Copyright 2012-present OSBI Ltd
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

// Packages
import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { isBoolean } from 'lodash';
import { Button, Classes, Dialog, FormGroup, Intent } from '@blueprintjs/core';
import Select from 'react-select';

// Actions
import { actionCreators } from '../../../actions';

// UI
import { ErrorMessage, Loading } from '../../UI';

// Utils
import { Settings } from '../../../utils';

// Constants
const { SAIKU_COLOR } = Settings;

class CubesDialog extends Component {
  state = {
    schemas: [],
    selectedSchema: null,
    cubes: [],
    selectedCube: null,
    isDisabledSelectCubes: true,
    isDisabledActionBtn: true,
    loading: true,
    error: false
  };

  componentWillMount() {
    this.callSchemasAndCubes();
  }

  callSchemasAndCubes = () => {
    this.setState({
      loading: true,
      error: false
    });

    this.getSchemasAndCubes()
      .then(data => {
        const { query } = this.props;
        const { schemas, cubes } = data;

        this.setState({ schemas, cubes, loading: false });

        if (query && query.cube) {
          const { cube } = query;

          this.setState({
            selectedSchema: this.getSelectedSchema(cube),
            selectedCube: {
              cube,
              ...this.getSelectedCube(cube)
            },
            isDisabledSelectCubes: false,
            isDisabledActionBtn: false
          });
        }
      })
      .catch(error => this.setState({ loading: false, error: true }));
  };

  async getSchemasAndCubes() {
    const { datasources } = this.props;
    const dataSchemas = [];
    const dataCubes = {};

    await datasources.forEach(datasource => {
      datasource.catalogs.forEach(catalog => {
        catalog.schemas.forEach(schema => {
          const schemaName = schema.name !== '' ? schema.name : catalog.name;

          dataSchemas.push({
            value: schemaName,
            label: schemaName
          });

          dataCubes[schemaName] = [];

          schema.cubes.forEach(cube => {
            if (
              (isBoolean(cube.visible) && cube.visible) ||
              cube.visible === 'true'
            ) {
              dataCubes[schemaName].push({
                value: `${datasource.name}/${catalog.name}/${
                  schema.name === '' || schema.name === null
                    ? 'null'
                    : schema.name
                }/${encodeURIComponent(cube.name)}`,
                label: `${
                  cube.caption === '' || cube.caption === null
                    ? cube.name
                    : cube.caption
                }`,
                cube
              });
            }
          });
        });
      });
    });

    return { schemas: dataSchemas, cubes: dataCubes };
  }

  getSelectedSchema(cube) {
    const schemaName = cube.schema !== '' ? cube.schema : cube.catalog;

    return {
      value: schemaName,
      label: schemaName
    };
  }

  getSelectedCube(cube) {
    return {
      value: `${cube.connection}/${cube.catalog}/${
        cube.schema === '' || cube.schema === null ? 'null' : cube.schema
      }/${encodeURIComponent(cube.name)}`,
      label: `${
        cube.caption === '' || cube.caption === null ? cube.name : cube.caption
      }`
    };
  }

  handleChangeSchemas(schema) {
    if (schema) {
      this.setState({
        selectedSchema: schema,
        selectedCube: null,
        isDisabledSelectCubes: false,
        isDisabledActionBtn: true
      });
    } else {
      this.setState({
        selectedSchema: null,
        selectedCube: null,
        isDisabledSelectCubes: true,
        isDisabledActionBtn: true
      });
    }
  }

  handleChangeCubes(cube) {
    if (cube) {
      this.setState({ selectedCube: cube, isDisabledActionBtn: false });
    } else {
      this.setState({
        selectedCube: null,
        isDisabledSelectCubes: true,
        isDisabledActionBtn: true
      });
    }
  }

  handleSave = () => {
    const { query, newQuery, saveSelectedCube, onClose } = this.props;
    const { cube } = this.state.selectedCube;
    const selectedCube = this.state.selectedCube.value;

    if (query && !query.cube) {
      newQuery(cube);
    } else if (query && query.cube && query.cube.name === cube.name) {
      newQuery(cube);
    } else {
      newQuery(cube, true);
    }

    saveSelectedCube(selectedCube);
    onClose();
  };

  renderForm() {
    const {
      schemas,
      selectedSchema,
      selectedCube,
      cubes,
      isDisabledSelectCubes
    } = this.state;

    return (
      <Fragment>
        <FormGroup label="Select a schema" labelFor="schemas">
          <Select
            options={schemas}
            value={selectedSchema}
            onChange={schema => this.handleChangeSchemas(schema)}
            styles={{
              control: (styles, state) => ({
                ...styles,
                borderColor: state.isFocused ? SAIKU_COLOR : '#ccc',
                boxShadow: state.isFocused ? `0 0 0 1px ${SAIKU_COLOR}` : null,
                ':hover': {
                  ...styles[':hover'],
                  borderColor: state.isFocused ? SAIKU_COLOR : '#ccc'
                }
              }),
              option: (styles, state) => ({
                ...styles,
                backgroundColor: state.isSelected ? SAIKU_COLOR : null,
                ':hover': {
                  ...styles[':hover'],
                  backgroundColor: state.isSelected ? SAIKU_COLOR : '#e1ddff'
                },
                ':active': {
                  ...styles[':active'],
                  backgroundColor: state.isSelected ? SAIKU_COLOR : null
                }
              })
            }}
            isSearchable
          />
        </FormGroup>

        <FormGroup label="Select a cube" labelFor="cubes">
          <Select
            options={selectedSchema ? cubes[selectedSchema.value] : []}
            value={selectedCube}
            isDisabled={isDisabledSelectCubes}
            onChange={cube => this.handleChangeCubes(cube)}
            styles={{
              control: (styles, state) => ({
                ...styles,
                borderColor: state.isFocused ? SAIKU_COLOR : '#ccc',
                boxShadow: state.isFocused ? `0 0 0 1px ${SAIKU_COLOR}` : null,
                ':hover': {
                  ...styles[':hover'],
                  borderColor: state.isFocused ? SAIKU_COLOR : '#ccc'
                }
              }),
              option: (styles, state) => ({
                ...styles,
                backgroundColor: state.isSelected ? SAIKU_COLOR : null,
                ':hover': {
                  ...styles[':hover'],
                  backgroundColor: state.isSelected ? SAIKU_COLOR : '#e1ddff'
                },
                ':active': {
                  ...styles[':active'],
                  backgroundColor: state.isSelected ? SAIKU_COLOR : null
                }
              })
            }}
            isSearchable
          />
        </FormGroup>
      </Fragment>
    );
  }

  render() {
    const { onClose } = this.props;
    const { isDisabledActionBtn, loading, error, errorMsg } = this.state;

    return (
      <Dialog
        title="Select Cube"
        icon="cube"
        canOutsideClickClose={false}
        isOpen={true}
        onClose={onClose}
      >
        <div className={Classes.DIALOG_BODY}>
          {loading ? (
            <Loading size={30} center />
          ) : error ? (
            <ErrorMessage text={errorMsg} callApi={this.callSchemasAndCubes} />
          ) : (
            this.renderForm()
          )}
        </div>

        {!loading && !error && (
          <div className={Classes.DIALOG_FOOTER}>
            <div className={Classes.DIALOG_FOOTER_ACTIONS}>
              <Button
                text="Ok"
                intent={Intent.DANGER}
                disabled={isDisabledActionBtn}
                onClick={this.handleSave}
              />
              <Button text="Close" onClick={onClose} />
            </div>
          </div>
        )}
      </Dialog>
    );
  }
}

CubesDialog.propTypes = {
  datasources: PropTypes.array.isRequired,
  query: PropTypes.object.isRequired,
  newQuery: PropTypes.func.isRequired,
  saveSelectedCube: PropTypes.func.isRequired,
  onClose: PropTypes.func.isRequired
};

const mapStateToProps = state => ({
  ...state.datasources,
  ...state.query
});

const mapDispatchToProps = dispatch => ({
  newQuery: (cube, forceResetQuery) =>
    dispatch(actionCreators.newQuery(cube, forceResetQuery)),
  saveSelectedCube: selectedCube =>
    dispatch(actionCreators.saveSelectedCube(selectedCube))
});

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(CubesDialog);
